package galaxy

import (
	"fmt"
	"os"
	"path"
	"strings"
	"time"

	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/def"
	"github.com/sirupsen/logrus"
)

type rootLogger struct {
	logger *logrus.Logger
	logrus.Formatter

	file   *os.File
	ticker *time.Ticker
}

type Logger struct {
	logger *logrus.Logger
	entry  *logrus.Entry
}

func (l *rootLogger) init() {
	l.logger = logrus.New()
	l.Formatter = &logrus.JSONFormatter{}

	l.logger.SetOutput(os.Stderr)
	l.logger.SetLevel(logrus.DebugLevel)
}

func (l *rootLogger) bindFile(fileName string) error {
	l.logger.SetFormatter(&logrus.TextFormatter{DisableColors: true})

	if err := l.getFile(fileName); err != nil {
		return err
	}
	go func() {
		now := time.Now()
		// 最小间隔1小时一个文件， 先只按时间，不安大小
		<-time.After(time.Minute*time.Duration(60-now.Minute()) + time.Second*time.Duration(61-now.Second()))
		_ = l.getFile(fileName)
		ticker := time.NewTicker(time.Minute * 24)
		l.ticker = ticker
		for _ = range ticker.C {
			// 重新调整文件
			_ = l.getFile(fileName)
		}
	}()
	return nil
}

func (l *rootLogger) getFile(fileName string) error {
	now := time.Now()
	fileName = strings.Replace(fileName, "%p", utils.ToString(os.Getpid()), 1)
	fileName = strings.Replace(fileName, "%Y", utils.ToString(now.Year()), 1)
	fileName = strings.Replace(fileName, "%M", fmt.Sprintf("%02d", now.Month()), 1)
	fileName = strings.Replace(fileName, "%D", fmt.Sprintf("%02d", now.Day()), 1)
	fileName = strings.Replace(fileName, "%H", fmt.Sprintf("%02d", now.Hour()), 1)
	dir := path.Dir(fileName)
	if err := utils.Mkdir(dir); err != nil {
		return err
	}
	if file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644); err != nil {
		return err
	} else {
		l.logger.SetOutput(file)
		// 关闭原有文件
		if l.file != nil {
			_ = l.file.Close()
		}
		l.file = file
	}
	return nil
}

func (l *rootLogger) exit() {
	if l.file != nil {
		_ = l.file.Close()
		l.file = nil
		l.logger.SetOutput(os.Stderr)
	}
}

func (l *rootLogger) Logger() def.Logger {
	return &Logger{l.logger, l.logger.WithFields(logrus.Fields{})}
}

func (l *Logger) LoggerWrap(key string, context string) def.Logger {
	return &Logger{l.logger, l.entry.WithField(key, context)}
}

func (l *Logger) LoggerFields(meta map[string]interface{}) def.Logger {
	return &Logger{l.logger, l.entry.WithFields(meta)}
}

func (l *Logger) Debugf(format string, args ...interface{}) {
	l.entry.Debugf(format, args...)
}
func (l *Logger) Infof(format string, args ...interface{}) {
	l.entry.Infof(format, args...)
}

func (l *Logger) Printf(format string, args ...interface{}) {
	l.entry.Printf(format, args...)
}
func (l *Logger) Warnf(format string, args ...interface{}) {
	l.entry.Warnf(format, args...)
}
func (l *Logger) Warningf(format string, args ...interface{}) {
	l.entry.Warningf(format, args...)
}
func (l *Logger) Errorf(format string, args ...interface{}) {
	l.entry.Errorf(format, args...)
}
func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.entry.Fatalf(format, args...)
}
func (l *Logger) Panicf(format string, args ...interface{}) {
	l.entry.Panicf(format, args...)
}

func (l *Logger) Debug(args ...interface{}) {
	l.entry.Debug(args...)
}
func (l *Logger) Info(args ...interface{}) {
	l.entry.Info(args...)
}
func (l *Logger) Print(args ...interface{}) {
	l.entry.Print(args...)
}
func (l *Logger) Warn(args ...interface{}) {
	l.entry.Warn(args...)
}
func (l *Logger) Warning(args ...interface{}) {
	l.entry.Warning(args...)
}
func (l *Logger) Error(args ...interface{}) {
	l.entry.Error(args...)
}
func (l *Logger) Fatal(args ...interface{}) {
	l.entry.Fatal(args...)
}
func (l *Logger) Panic(args ...interface{}) {
	l.entry.Panic(args...)
}

func (l *Logger) Debugln(args ...interface{}) {
	l.entry.Debugln(args...)
}
func (l *Logger) Infoln(args ...interface{}) {
	l.entry.Infoln(args...)
}
func (l *Logger) Println(args ...interface{}) {
	l.entry.Println(args...)
}
func (l *Logger) Warnln(args ...interface{}) {
	l.entry.Warnln(args...)
}
func (l *Logger) Warningln(args ...interface{}) {
	l.entry.Warningln(args...)
}
func (l *Logger) Errorln(args ...interface{}) {
	l.entry.Errorln(args...)
}
func (l *Logger) Fatalln(args ...interface{}) {
	l.entry.Fatalln(args...)
}
func (l *Logger) Panicln(args ...interface{}) {
	l.entry.Panicln(args...)
}
